package dk.itu.mario.level.generator;

import java.util.Random;

import dk.itu.mario.MarioInterface.Constraints;
import dk.itu.mario.MarioInterface.GamePlay;
import dk.itu.mario.MarioInterface.LevelGenerator;
import dk.itu.mario.MarioInterface.LevelInterface;
import dk.itu.mario.level.CustomizedLevel;
import dk.itu.mario.level.MyLevel;

public class MyLevelGenerator extends CustomizedLevelGenerator implements LevelGenerator{

	private Random random;
	
	public LevelInterface generateLevel(GamePlay playerMetrics) {
		//LevelInterface level = new MyLevel(320,15,new Random().nextLong(),1,LevelInterface.TYPE_OVERGROUND,playerMetrics);

		LevelInterface level = new MyLevel(320,15,12345,2,LevelInterface.TYPE_OVERGROUND,playerMetrics);

		
//		try {
//			level = this.simulatedAnnealing(level, playerMetrics);
//		} 
//		catch (CloneNotSupportedException e) {
//			e.printStackTrace();
//		}
		
		
		/*MyLevel asdf = (MyLevel)level;
		for(int i=0; i<20; i++) {
			double eval1 = asdf.eval(playerMetrics);
			System.out.println("oldEval: "+eval1);
			MyLevel asdf2 = asdf.perturb(playerMetrics);
			double eval2 = asdf2.eval(playerMetrics);
			System.out.println("newEval: "+eval2);
			
			if(eval2 < eval1){
				System.out.println("Chose new level\n");
				asdf = asdf2;
			}
			else {
				System.out.println("Kept old level\n");
			}
		}
		System.out.println("\nFinal Eval: "+asdf.eval(playerMetrics));
		return asdf;*/

			
		//System.out.println("Eval: "+asdf.eval(playerMetrics));

		
		//return level;
		return simulatedAnnealing(level, playerMetrics);
	}
	
	public LevelInterface simulatedAnnealing(LevelInterface l, GamePlay player){
		MyLevel level = (MyLevel) l; //Initial solution
		MyLevel bestLevel = level; //Keeps running best solution
		int bestIter = 0;
		double temp = 0.3; //Initial temperature
		double coolingRate = 0.98;
		int iterations = 150;
		double iterRate = 1.02;
		int totalIter = 1500;
		int numIters = 0;

		if(random == null)
			random = new Random();
				
		while (numIters < totalIter) {
			for (int i = 0; i < iterations; i++) {
				numIters++;
				MyLevel newLevel = level.perturb(player);
				//System.out.println("oldEval: "+level.eval(player));
				//System.out.println("newEval: "+newLevel.eval(player));
				if ((newLevel.eval(player) < level.eval(player)) ||
						(random.nextDouble() < Math.exp((level.eval(player)-newLevel.eval(player))/temp))) {
					level = newLevel;
					//System.out.println("Chose new level");
					if (level.eval(player) < bestLevel.eval(player)) {
						bestLevel = level;
						bestIter = numIters-1;
					}
				}
				//else System.out.println("Kept old level");
				//System.out.println("------------------\n");
				
			}
			temp *= coolingRate;
			iterations *= iterRate;
		}
		
		System.out.println("\nBest Eval: "+bestLevel.eval(player));
		System.out.println("best found at iteration: "+bestIter);
		return bestLevel;
	}

	@Override
	public LevelInterface generateLevel(String detailedInfo) {
		// TODO Auto-generated method stub
		return null;
	}

}
